using Bases;
using Configs;
using Inputs;
using Modules.Game.Skills;
using UnityEngine;
using UnityEngine.AI;
using Utils;

namespace Modules.Game.Roles
{
    public class Hero : MonoBehaviourSimplify
    {
        private static readonly int AnimSpeed = Animator.StringToHash("speed");

        public GameObject skillGuide;
        public GameObject model;

        public Vector3 targetPos;

        private NavMeshAgent _agent;
        private Animator _anim;

        /// <summary>
        ///     准备中的技能下标
        /// </summary>
        private int _readySkillIndex;

        private float _time;

        private void Awake()
        {
            _agent = model.GetComponent<NavMeshAgent>();
            _anim = model.GetComponent<Animator>();

            _agent.SetDestination(targetPos);

            PlayerInput.Instance.MoveAction += OnMove;
            PlayerInput.Instance.SelectAction += OnSelect;
            PlayerInput.Instance.ReadySkillAction += OnReadySkill;
            PlayerInput.Instance.ReleaseSkillAction += OnReleaseSkill;
        }

        private void Update()
        {
            if (!GameModel.Instance.IsGaming) return;

            if (GetHorizontalDistance(targetPos, model.transform.position) < 0.2f)
                _agent.Move(targetPos - model.transform.position);

            _anim.SetFloat(AnimSpeed, _agent.velocity.magnitude);

            var dt = Time.deltaTime;
            HeroModel.Instance.UpdateFrame(dt);
            UpdateSecond(dt);
        }

        protected override void OnBeforeDestroy()
        {
            if (PlayerInput.IsExist)
            {
                PlayerInput.Instance.MoveAction -= OnMove;
                PlayerInput.Instance.ReadySkillAction -= OnReadySkill;
                PlayerInput.Instance.ReleaseSkillAction -= OnReleaseSkill;
            }
        }

        private void UpdateSecond(float dt)
        {
            _time += dt;
            if (_time < 1.0f)
                return;

            _time = 0.0f;
            HeroModel.Instance.UpdateSecond();
        }

        private float GetHorizontalDistance(Vector3 vec1, Vector3 vec2)
        {
            vec1.y = 0;
            vec2.y = 0;
            return (vec2 - vec1).magnitude;
        }

        private void OnMove(Vector3 moveTargetPos)
        {
            targetPos = moveTargetPos;
            _agent.SetDestination(targetPos);
        }

        private void OnSelect(Vector3 selectTargetPos)
        {
            // 处理技能
            if (skillGuide.activeSelf)
            {
                var skillRange = skillGuide.GetComponent<SkillGuide>().GetSkillRange();

                if ((selectTargetPos - GetHeroPos()).magnitude > skillRange)
                    // 取消技能
                    skillGuide.SetActive(false);
                else
                    // 释放技能
                    OnReleaseSkill(_readySkillIndex);
            }
        }

        /// <summary>
        ///     准备技能
        /// </summary>
        /// <param name="order">技能下标</param>
        private void OnReadySkill(int order)
        {
            var skillData = HeroModel.Instance.GetSkillData(order);
            if (skillData.Cd > 0)
            {
                MsgDispatcher.Send(EventConfig.OpenTip, skillData.Name + " Cd中");
                return;
            }

            // 检测技能消耗
            if (HeroModel.Instance.Data.Attr.CurMp < skillData.Attr.Mp)
            {
                MsgDispatcher.Send(EventConfig.OpenTip, "缺蓝");
                return;
            }

            _readySkillIndex = order;

            skillGuide.SetActive(true);
            skillGuide.GetComponent<SkillGuide>().SetSkillRange(skillData.Range);
        }

        /// <summary>
        ///     释放技能
        /// </summary>
        /// <param name="order">技能下标</param>
        private void OnReleaseSkill(int order)
        {
            if (!skillGuide.activeSelf) return;

            skillGuide.SetActive(false);

            GameModule.Instance.OnReleaseSkill(order);
        }

        public Vector3 GetHeroPos()
        {
            return model.transform.position;
        }

        public GameObject GetModel()
        {
            return model;
        }
    }
}